﻿using K9Nano.Caching;
using K9Nano.Domain.Entities;
using K9Nano.Mapping;
using MapsterMapper;

namespace K9Nano.Domain.Caching;

public abstract class AbstractEntityCache<TEntity, TEntityCacheItem> : IEntityCache<TEntity, TEntityCacheItem>
    where TEntity : class, IEntity
    where TEntityCacheItem : class
{
    protected readonly ITypedCache<TEntityCacheItem> Cache;

    protected AbstractEntityCache(ITypedCache<TEntityCacheItem> cache)
    {
        Cache = cache;
    }

    protected virtual string GetCacheKey(long key) => key.ToString();

    public virtual TEntityCacheItem? Get(long key)
    {
        var cacheKey = GetCacheKey(key);
        var result = Cache.Get(cacheKey);
        if (result == null)
        {
            var entity = GetEntity(key);
            if (entity != null!)
            {
                result = MapToCacheItem(entity);
                if (result == null)
                {
                    throw new Exception($"CacheValue of {entity}:{key} can not be null");
                }
                Cache.AddOrUpdate(cacheKey, result, _ => result);
            }
        }
        return result;
    }

    protected virtual TEntityCacheItem MapToCacheItem(TEntity entity)
    {
        return MappingHelper.Mapper.Map<TEntityCacheItem>(entity);
    }

    protected abstract TEntity GetEntity(long key);
}